package com.ganmiao.utils;

import javax.servlet.http.HttpServletRequest;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Pattern;

public class IpUtil
{
    
    private static final Pattern IP_PATTERN = Pattern.compile("([0-9]{1,3}\\.){3}[0-9]{1,3}");
    
    /**
     * 取客户端的真实ip，考虑了反向代理等因素的干扰
     */
    public static String getIpAddr(HttpServletRequest request)
    {
        String xff = request.getHeader("X-Forwarded-For");
        String ip = resolveClientIPFromXFF(xff);
        if(isValidIP(ip))
        {
            return ip;
        }
        ip = request.getHeader("Proxy-Client-IP");
        if(isValidIP(ip))
        {
            return ip;
        }
        ip = request.getHeader("WL-Proxy-Client-IP");
        if(isValidIP(ip))
        {
            return ip;
        }
        return request.getRemoteAddr();
    }
    
    /**
     * 从X-Forwarded-For头部中获取客户端的真实IP。
     * X-Forwarded-For并不是RFC定义的标准HTTP请求Header，可以参考http://en.wikipedia.org/wiki/X-Forwarded-For
     *
     * @param xff X-Forwarded-For头部的值
     * @return 如果能够解析到client IP，则返回表示该IP的字符串，否则返回null
     */
    private static String resolveClientIPFromXFF(String xff)
    {
        if(xff == null || xff.length() == 0)
        {
            return null;
        }
        String[] ss = xff.split(",");
        for(String ip : ss)
        {
            ip = ip.trim();
            if(isValidIP(ip))
            {
                return ip;
            }
        }
        return null;
    }
    
    /**
     * long ip to string
     */
    public static String iplongToIp(long ipaddress)
    {
        StringBuffer sb = new StringBuffer("");
        sb.append(String.valueOf((ipaddress >>> 24)));
        sb.append(".");
        sb.append(String.valueOf((ipaddress & 0x00FFFFFF) >>> 16));
        sb.append(".");
        sb.append(String.valueOf((ipaddress & 0x0000FFFF) >>> 8));
        sb.append(".");
        sb.append(String.valueOf((ipaddress & 0x000000FF)));
        return sb.toString();
    }
    
    /**
     * string ip to long
     */
    public static long ipStrToLong(String ipaddress)
    {
        long[] ip = new long[4];
        int position1 = ipaddress.indexOf(".");
        int position2 = ipaddress.indexOf(".", position1 + 1);
        int position3 = ipaddress.indexOf(".", position2 + 1);
        ip[0] = Long.parseLong(ipaddress.substring(0, position1));
        ip[1] = Long.parseLong(ipaddress.substring(position1 + 1, position2));
        ip[2] = Long.parseLong(ipaddress.substring(position2 + 1, position3));
        ip[3] = Long.parseLong(ipaddress.substring(position3 + 1));
        return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];
    }
    
    /**
     * 检查是否是一个合格的ipv4 ip
     */
    public static boolean isValidIP(String ip)
    {
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            return false;
        }
        return IP_PATTERN.matcher(ip).matches();
    }
    
    /**
     * 取得一个合格的ipv4 ip,外网ip
     */
    public static String getLocalIP()
    {
        for(String a : getAllNoLoopbackAddresses())
        {
            if(isValidIP(a))
            {
                return a;
            }
        }
        return "";
    }
    
    /**
     * 获取本地地址 内网ip
     *
     * @return 本机ipv4地址
     */
    public static final String getLocalAddress()
    {
        try
        {
            for(Enumeration<NetworkInterface> ni = NetworkInterface.getNetworkInterfaces(); ni.hasMoreElements();)
            {
                NetworkInterface eth = ni.nextElement();
                for(Enumeration<InetAddress> add = eth.getInetAddresses(); add.hasMoreElements();)
                {
                    InetAddress i = add.nextElement();
                    if(i instanceof Inet4Address)
                    {
                        if(i.isSiteLocalAddress())
                        {
                            return i.getHostAddress();
                        }
                    }
                }
            }
        }
        catch (SocketException e)
        {
            e.printStackTrace();
        }
        return "";
    }
    
    /**
     * 取得本地所有的ipv4列表
     */
    public static List<String> getLocalIPs()
    {
        List<String> localIps = new ArrayList<String>();
        for(String a : getAllNoLoopbackAddresses())
        {
            if(isValidIP(a))
            {
                localIps.add(a);
            }
        }
        return localIps;
    }
    
    private static Collection<InetAddress> getAllHostAddress()
    {
        try
        {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            Collection<InetAddress> addresses = new ArrayList<InetAddress>();
            
            while (networkInterfaces.hasMoreElements())
            {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
                while (inetAddresses.hasMoreElements())
                {
                    InetAddress inetAddress = inetAddresses.nextElement();
                    addresses.add(inetAddress);
                }
            }
            
            return addresses;
            
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }
    
    private static Collection<String> getAllNoLoopbackAddresses()
    {
        Collection<String> noLoopbackAddresses = new ArrayList<String>();
        Collection<InetAddress> allInetAddresses = getAllHostAddress();
        
        for(InetAddress address : allInetAddresses)
        {
            if(!address.isLoopbackAddress())
            {
                noLoopbackAddresses.add(address.getHostAddress());
            }
        }
        
        return noLoopbackAddresses;
    }
}
